import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;

/**
 * Window in which game will take place.
 * @author wlis
 */
public class Window extends JFrame{
	private static final long serialVersionUID = 7496192696420361406L;

	/**
	 * Prepares window and its menu
	 * @param name text that will be set for name of window
	 */
	public Window(String name)
	{
		super(name);
		this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		getContentPane().setLayout(new FlowLayout());
		myFiles = new JFileChooser();
		myFiles.setCurrentDirectory(new File("./boards"));
		
		this.setSize(640, 480);
		this.setResizable(false);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		
		menuBar = new JMenuBar();
		setJMenuBar(menuBar);
		
		mnFile = new JMenu("File");
		menuBar.add(mnFile);
		
		mnEdit = new JMenu("Edit");
		menuBar.add(mnEdit);
		
		mnEditor = new JMenu("Editor");
		menuBar.add(mnEditor);
		
		JMenuItem mntmChooseBoard = new JMenuItem("Choose board");
		
		mntmChooseBoard.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent evt)
			{
				chooseBoardPerformed(evt);
			}
		});
		mnFile.add(mntmChooseBoard);
		
		JMenuItem mntmNewGame = new JMenuItem("Restart");
		mntmNewGame.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent evt)
			{
				restartGamePerformed(evt);
			}
		});
		mnFile.add(mntmNewGame);
		
		JMenuItem mntmCreateBoard = new JMenuItem("Create board");
		mntmCreateBoard.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent evt)
			{
				createBoardPerformed(evt);
			}
		});
		mnEditor.add(mntmCreateBoard);
		
		JMenuItem mntmEditBoard = new JMenuItem("Edit board");
		editExistingBoardListener editListener = new editExistingBoardListener(this);
		mntmEditBoard.addActionListener(editListener);
		mnEditor.add(mntmEditBoard);
		
		JMenuItem mntmGraphicsOptions = new JMenuItem("Graphics Options");
		mntmGraphicsOptions.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent evt) {
				graphicsOptionsPerformed(evt);
			}
		});
		mnEdit.add(mntmGraphicsOptions);
		
		JMenuItem mntmKeyBindings = new JMenuItem("Key Bindings");
		mntmKeyBindings.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent evt)
			{
				new KeyBindings(game);
			}
		});
		mnEdit.add(mntmKeyBindings);
		
		this.setVisible(true);
	}


	class editExistingBoardListener implements ActionListener
	{
		JFrame frame;
		editExistingBoardListener(JFrame frame)
		{
			this.frame = frame;
		}
		Board board;
		@Override
		public void actionPerformed(ActionEvent evt) {
			int result = myFiles.showOpenDialog(frame);
			if (result == JFileChooser.APPROVE_OPTION) {
				try{
					board = new Board(myFiles.getSelectedFile(), 1);
	            } catch (Exception e) {
	                JOptionPane.showMessageDialog(frame, "Reading of board failed!", "ERROR", JOptionPane.ERROR_MESSAGE);
	            }
			}
			unloadGame();
			unloadProject();
			board.validate();
			board.addFieldsListeners();
			project = new Project(frame, board);
			getContentPane().add(project);
			frame.validate();
			fixSize();
			frame.repaint();
		}
	}

	
	private void graphicsOptionsPerformed(ActionEvent evt){
		new GraphicsOptions(this);
	}
	
	/**
	 * Allows to choose the board to play.
	 * @param evt type of event performed on button
	 */
	private void chooseBoardPerformed(ActionEvent evt)
	{
		int result = myFiles.showOpenDialog(this);
		if (result == JFileChooser.APPROVE_OPTION) {
			unloadGame();
			unloadProject();
			this.validate();
			loadGame();
        	 try {
            	game.initializeBoard(myFiles.getSelectedFile());
            	game.setFile(myFiles.getSelectedFile());
            	this.validate();           	
              	fixSize();
            	this.repaint();
            } catch (Exception e) {
                JOptionPane.showMessageDialog(this, "Reading of board failed!", "ERROR", JOptionPane.ERROR_MESSAGE);
            }
            
		}
	}
	/**
	 * Restarts game.
	 * @param evt type of event performed on button
	 */
	private void restartGamePerformed(ActionEvent evt)
	{
		try {
			this.game.restartGame();
		} catch (NoBoardLoadedException e) {
			JOptionPane.showMessageDialog(this, "Choose board first!", "ERROR", JOptionPane.ERROR_MESSAGE);
			e.printStackTrace();
		} catch (Exception e)
		{
			JOptionPane.showMessageDialog(this, "Reading of board failed!", "ERROR", JOptionPane.ERROR_MESSAGE);
		}
	}
	/**
	 * Prepares GUI for creating new board.
	 * @param evt
	 */
	private void createBoardPerformed(ActionEvent evt)
	{
		unloadGame();
		unloadProject();
		loadProject();
		this.setSize(640, 480);
		this.repaint();
	}
	/**
	 * Adds JMenuItem to menuBar
	 * @param item
	 */
	void addMenuItem(JMenuItem item)
	{
		mnFile.add(item);
		this.repaint();
	}
	/**
	 * Removes JMenuItem from menuBar
	 * @param item
	 */
	void removeMenuItem(JMenuItem item)
	{
		if(item != null)
		{
			mnFile.remove(item);
		}
		this.repaint();
	}
	
	
	private void loadProject()
	{
		this.project = new Project(this);
		getContentPane().add(project);
		this.validate();
	}
	private void loadGame()
	{
		game = new Game();
		getContentPane().add(game);
		game.grabFocus();
		
		this.validate();
	}
	private void unloadGame()
	{
		if(game != null){
			game.finishGame();
			this.removeKeyListener(game.keyListener);
			this.removeKeyListener(game.keyListener2);
			this.remove(game);
		}
		game = null;
		this.validate();
	}
	private void unloadProject()
	{
		if(project != null)
		{
			project.clearMenuBar();
			this.remove(project);
		}
		project = null;
		this.validate();
	}
	/**
	 * @return Window's file chooser.
	 */
	JFileChooser getDirectory()
	{
		return myFiles;
	}
	/**
	 * Fixes size of window according to its content.
	 */
	public void fixSize()
	{
		if(game != null)this.setSize(game.getWidth()> 100? game.getWidth(): 100, game.getHeight() + menuBar.getHeight() + 33); //33 is a mysterious count, that makes everything fit :)
		else if(project != null)this.setSize(project.getWidth()> 100? project.getWidth(): 100, project.getHeight() + menuBar.getHeight() + 33); //33 is a mysterious count, that makes everything fit :)
	}
	private JFileChooser myFiles;
	private Game game;
	private Project project;
	private JMenuBar menuBar;
	private JMenu mnFile, mnEdit, mnEditor;
}